#include "../inc/CentralCache.h"
#include "../inc/threadCache.h"
#include <cstdlib>

using namespace std;

namespace memoryPoolV2 {
void *ThreadCache::allocate(size_t size) {
    if (size == 0)
        size = ALIGNMENT;

    if (size > MAX_BYTES)
        return malloc(size);

    size_t index = SizeClass::getIndex(size);
    freeListSize_[index]--;

    // 检查线程本地自由链表，不为空说明有可用内存块
    if (void *ptr = freeList_[index]) {
        freeList_[index] = *reinterpret_cast<void **>(ptr);
        return ptr;
    }

    // 本地空，从centralcache获取一批内存
    return fetchFromCentralCache(index);
}

void ThreadCache::deallocate(void *ptr, size_t size) {
    if (size > MAX_BYTES) {
        free(ptr);
        return;
    }

    size_t index = SizeClass::getIndex(size);

    // 插入线程到本地自由链表
    *reinterpret_cast<void **>(ptr) = freeList_[index];
    freeList_[index] = ptr;

    if (shouldReturnToCentralCache(index))
        returnToCentralCache(freeList_[index], size);
}

bool ThreadCache::shouldReturnToCentralCache(size_t index) {
    // 设定阈值
    size_t threshold = 64;
    return (freeListSize_[index] > threshold);
}

void *ThreadCache::fetchFromCentralCache(size_t index) {
    // 从中心缓存批量获取内存
    void *start = CentralCache::getInstance().fetchRange(index);
    if (!start)
        return nullptr;

    void *result = start;
    freeList_[index] = *reinterpret_cast<void **>(start);

    // 更新自由链表大小
    std::size_t batchNum = 0;
    void *cur = start;

    while (cur != nullptr) {
        batchNum++;
        cur = *reinterpret_cast<void **>(cur); // 下一个内存块
    }

    freeListSize_[index] += batchNum;

    return result;
}

void ThreadCache::returnToCentralCache(void *start, size_t size) {
    // 初始地址，每块大小
    //  根据大小计算索引
    std::size_t index = SizeClass::getIndex(size);

    // 获取对齐后的实际块大小
    std::size_t alignedSize = SizeClass::roundUp(size);

    // 计算要归还内存块数量
    std::size_t batchNum = freeListSize_[index];

    // 保留部分在threadCache中
    if (batchNum <= 1)
        return;
    std::size_t keepNum = max(batchNum / 4, std::size_t(1));
    std::size_t returnNum = batchNum - keepNum;

    char *cur = static_cast<char *>(start);
    char *splitNode = cur; // 对齐后大小作为分割点
    for (std::size_t i = 0; i < keepNum - 1; i++) {
        splitNode = reinterpret_cast<char *>(*reinterpret_cast<void **>(splitNode));
        if (splitNode == nullptr) {
            returnNum = batchNum - (i + 1);
            break;
        }
    }

    if (splitNode != nullptr) {
        void *nextNode = *reinterpret_cast<void **>(splitNode);
        *reinterpret_cast<void **>(splitNode) = nullptr;

        freeList_[index] = start;
        freeListSize_[index] = keepNum;

        // 剩余部分还给CentralCache
        if (returnNum > 0 && nextNode != nullptr)
            CentralCache::getInstance().returnRange(nextNode, returnNum * alignedSize, index);
    }
}

} // namespace memoryPoolV2